package cn.hs.blog.base;

import java.beans.PropertyDescriptor;
import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.util.HashMap;
import java.util.Map;
import java.util.logging.Logger;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.commons.beanutils.BeanUtils;
import org.apache.commons.beanutils.ConstructorUtils;
import org.apache.commons.beanutils.MethodUtils;
import org.apache.commons.beanutils.PropertyUtils;

import cn.hs.blog.utils.StringUtil;

/**
 * hs Framework servlet 入口�?
 * 
 * @version $Revision$ $Date$
 * @author $Author$
 * 
 */
public class HsActionServlet extends HttpServlet {

    /**
     * 
     */
    private static final long serialVersionUID = 3095438492003590645L;

    private static final Logger log = Logger.getLogger(HsActionServlet.class.getName());

    private static final String PACKAGE_NAME = "cn.hs.";

    private static final String METHOD_NAME = "method";

    private static final String DEFAULT_METHOD = "execute";

    private static final String ACTION_PACKAGE_NAME = "action";
    
    private static final String SIGN = ".do";
    
    private static final Map<String, Object> actionCache = new HashMap<String, Object>();

    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp)
        throws ServletException,
            IOException {
        execute(req, resp);
    }

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp)
        throws ServletException,
            IOException {
        execute(req, resp);
    }

    /**
     * http 请求处理�?
     * 
     * @param req
     * @param resp
     * @throws ServletException
     * @throws IOException
     */
    public void execute(HttpServletRequest req, HttpServletResponse resp)
        throws ServletException,
            IOException {

        /** 处理请求的action实例 */
        Object action = null;
        
        String actionName = null;

        /**
         * 请求的Url �?path info 默认取request的path info
         */
        String pathInfo = getPathInfo(req);

        /**
         * 如果pathInfo为空 返回到错误页�?
         */
        if (StringUtil.isEmpty(pathInfo)) {
            // TODO 添加url为空的处�?
            return;
        }
        
        /** 处理请求的action实例中的方法 */
        String methodName = getMethodName(req);

        actionName = getActionName(pathInfo);
        if(actionName == null){
            log.warning("can't get name of the action!");
            return;
        }
        
        action = actionCache.get(actionName);
        if(action == null){
            /**
             * 通过actionName获得Action的实例
             */
            action = getActionByPathInfo(actionName);
            actionCache.put(actionName, action);
        }
        
        

        /**
         * 如果Action的实例为�?返回到错误页�?
         */
        if (action == null) {
            log.warning("can't find this action!");
            // TODO 添加action为空时的处理
            return;
        }

        /**
         * 初始化action中的属�?
         */
//        initEntity(action);

        /**
         * 将request中的参数绑定到action中的属�?
         */
//        populate(req, action);

        try {
            /**
             * 执行action中的方法
             */
            MethodUtils.invokeMethod(action, methodName, new Object[] { req, resp });
        } catch (NoSuchMethodException e) {
            log.warning(e.getLocalizedMessage());
            // e.printStackTrace();
        } catch (IllegalAccessException e) {
            log.warning(e.getMessage());
            // e.printStackTrace();
        } catch (InvocationTargetException e) {
            log.warning(e.getMessage());
            // e.printStackTrace();
        }

    }
    
    
    private String getPathInfo(HttpServletRequest req){
        /**
         * 请求的Url �?path info 默认取request的path info
         */
        String pathInfo = req.getPathInfo();

        /**
         * 如果从request中取的path info为空 则从request中取Servlet path
         */
        if (StringUtil.isEmpty(pathInfo)) {
            pathInfo = req.getServletPath();
        }

        log.info("pathInfo: " + pathInfo);
        
        return pathInfo;
    }

    /**
     * 根据pathInfo 获得 action的实�?
     * 
     * @param pathInfo
     * @return action的实�?
     */
    private Object getActionByPathInfo(String actionName) {        

        return getClassInstance(actionName);
    }
    
    private String getActionName(String pathInfo){
        String className = PACKAGE_NAME;

        String[] paths = pathInfo.split("/");
        if (paths == null || paths.length < 4) {
            return null;
        }
        
        paths[3] = paths[3].substring(0, paths[3].indexOf(SIGN));

        log.info("subSystem: " + paths[1]);
        log.info("moduleName: " + paths[2]);
        log.info("actionName: " + paths[3]);

        className += paths[1] + "." + paths[2] + "." + ACTION_PACKAGE_NAME + "." + paths[3] + "Action";
        log.info("className: " + className);
        
        return className;
    }

    private Object getClassInstance(String className) {
        Object result = null;
        try {
            result = Class.forName(className).newInstance();
        } catch (InstantiationException e) {
            log.warning(e.getMessage());
            // e.printStackTrace();
        } catch (IllegalAccessException e) {
            log.warning(e.getMessage());
            // e.printStackTrace();
        } catch (ClassNotFoundException e) {
            log.warning(e.getMessage());
            // e.printStackTrace();
        }

        if (result == null) {
            log.warning("class: " + className + " 不能获得实例 ");
        }
        return result;
    }

    /**
     * 从request中获得method的名�?如果没有返回默认的method名字
     * 
     * @param req
     * @return
     */
    private String getMethodName(HttpServletRequest req) {
        String result = req.getParameter(METHOD_NAME);

        if (StringUtil.isEmptyByTrim(result)) {
            result = DEFAULT_METHOD;
        }

        log.info("method: " + result);

        return result;
    }
    
    /**
     * 从request中获得method的名�?如果没有返回默认的method名字
     * 
     * @param req
     * @return
     */
    private String getMethodName(String pathInfo) {
        String result = null;

        String[] paths = pathInfo.split("/");
        if (paths == null || paths.length < 5 || StringUtil.isEmptyByTrim(paths[4])) {
            log.info("use default method: " + DEFAULT_METHOD);
            return DEFAULT_METHOD;
        }

        log.info("method: " + paths[4]);

        return paths[4];
    }

    /**
     * 用request中的数据填充obj中的属�?
     * 
     * @param request
     * @param obj
     */
    @SuppressWarnings("unchecked")
    public void populate(HttpServletRequest request, Object obj) {

        Map map = request.getParameterMap();
        try {
            BeanUtils.populate(obj, map);
        } catch (IllegalAccessException e) {
            log.warning(e.getMessage());
            // e.printStackTrace();
        } catch (InvocationTargetException e) {
            log.warning(e.getMessage());
            // e.printStackTrace();
        }
    }

    /**
     * 初始化obj的属�?
     * 
     * @param obj
     */
    private void initEntity(Object obj) {
        PropertyDescriptor[] propertyArray = PropertyUtils.getPropertyDescriptors(obj);
        for (PropertyDescriptor pd : propertyArray) {

            if (!pd.getName().equals("class")) {
                log.info("propertyName: " + pd.getName());
                Object instance = null;
                try {
                    instance = ConstructorUtils.invokeConstructor(pd.getPropertyType(), null);
                    BeanUtils.setProperty(obj, pd.getName(), instance);
                } catch (NoSuchMethodException e) {
                    log.warning(e.getMessage());
                    // e.printStackTrace();
                } catch (IllegalAccessException e) {
                    log.warning(e.getMessage());
                    // e.printStackTrace();
                } catch (InvocationTargetException e) {
                    log.warning(e.getMessage());
                    // e.printStackTrace();
                } catch (InstantiationException e) {
                    log.warning(e.getMessage());
                    // e.printStackTrace();
                }
            }

        }
    }

}
